From 108be1585379e86d0ab42e6f633fb5a7736b6524 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Wed, 14 Jul 2010 16:43:49 +0100 Subject: [PATCH] libxl: support mapping files rather than carrying paths around This will allow us to map and then unlink the file and therefore delete the process on process exit or explicit unmap. Using the mmaped versions of these files required rewriting build_pv to use the xc_dom builder functionality directly rather than through the xc_linux_build "compatibility layer". (The status of the xc_linux_build interface as a compatibility layer seems a bit dubious since all existing callers use it but if anything is going to replace it then libxl seems like the likely candidate). I'm not thrilled with the definition of the maps lifecycle. This could be solved by adding a helper function to explicitly free the toplevel structure. Signed-off-by: Ian Campbell --- tools/libxl/libxl.c | 69 +++++++++++++++++++++++++---- tools/libxl/libxl.h | 25 ++++++++++- tools/libxl/libxl_dom.c | 81 +++++++++++++++++++++++++++++----- tools/libxl/xl_cmdimpl.c | 12 ++--- tools/ocaml/libs/xl/xl_stubs.c | 4 +- 5 files changed, 162 insertions(+), 29 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 687a20e106..bd39454ca7 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include /* for write, unlink and close */ @@ -291,12 +292,12 @@ int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uin vments[i++] = "image/ostype"; vments[i++] = "linux"; vments[i++] = "image/kernel"; - vments[i++] = (char*) info->kernel; + vments[i++] = (char*) info->kernel.path; vments[i++] = "start_time"; vments[i++] = libxl_sprintf(ctx, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000); - if (info->u.pv.ramdisk) { + if (info->u.pv.ramdisk.path) { vments[i++] = "image/ramdisk"; - vments[i++] = (char*) info->u.pv.ramdisk; + vments[i++] = (char*) info->u.pv.ramdisk.path; } if (info->u.pv.cmdline) { vments[i++] = "image/cmdline"; @@ -305,6 +306,10 @@ int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uin } ret = build_post(ctx, domid, info, state, vments, localents); out: + libxl_file_reference_unmap(ctx, &info->kernel); + if (!info->hvm) + libxl_file_reference_unmap(ctx, &info->u.pv.ramdisk); + return ret; } @@ -338,12 +343,12 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info, vments[i++] = "image/ostype"; vments[i++] = "linux"; vments[i++] = "image/kernel"; - vments[i++] = (char*) info->kernel; + vments[i++] = (char*) info->kernel.path; vments[i++] = "start_time"; vments[i++] = libxl_sprintf(ctx, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000); - if (info->u.pv.ramdisk) { + if (info->u.pv.ramdisk.path) { vments[i++] = "image/ramdisk"; - vments[i++] = (char*) info->u.pv.ramdisk; + vments[i++] = (char*) info->u.pv.ramdisk.path; } if (info->u.pv.cmdline) { vments[i++] = "image/cmdline"; @@ -361,6 +366,10 @@ int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info, } out: + libxl_file_reference_unmap(ctx, &info->kernel); + if (!info->hvm) + libxl_file_reference_unmap(ctx, &info->u.pv.ramdisk); + esave = errno; flags = fcntl(fd, F_GETFL); @@ -1057,9 +1066,9 @@ static int libxl_create_stubdom(struct libxl_ctx *ctx, b_info.max_vcpus = 1; b_info.max_memkb = 32 * 1024; b_info.target_memkb = b_info.max_memkb; - b_info.kernel = libxl_abs_path(ctx, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path()); + b_info.kernel.path = libxl_abs_path(ctx, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path()); b_info.u.pv.cmdline = libxl_sprintf(ctx, " -d %d", info->domid); - b_info.u.pv.ramdisk = ""; + b_info.u.pv.ramdisk.path = ""; b_info.u.pv.features = ""; b_info.hvm = 0; @@ -3181,3 +3190,47 @@ int libxl_tmem_shared_auth(struct libxl_ctx *ctx, uint32_t domid, return rc; } +int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f) +{ + struct stat st_buf; + int ret, fd; + void *data; + + if (f->mapped) + return 0; + + fd = open(f->path, O_RDONLY); + if (f < 0) + return ERROR_FAIL; + + ret = fstat(fd, &st_buf); + if (ret < 0) + goto out; + + ret = -1; + data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == NULL) + goto out; + + f->mapped = 1; + f->data = data; + f->size = st_buf.st_size; + + ret = 0; +out: + close(fd); + + return ret == 0 ? 0 : ERROR_FAIL; +} + +int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f) +{ + int ret; + + if (!f->mapped) + return 0; + + ret = munmap(f->data, f->size); + + return ret == 0 ? 0 : ERROR_FAIL; +} diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 67ca8a751d..e58e9a5238 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -89,6 +89,24 @@ typedef struct { char *poolname; } libxl_domain_create_info; +typedef struct { + /* + * Path is always set if the file refernece is valid. However if + * mapped is true then the actual file may already be unlinked. + */ + char *path; + int mapped; + void *data; + size_t size; +} libxl_file_reference; + +/* + * Instances of libxl_file_reference contained in this struct which + * have been mapped (with libxl_file_reference_map) will be unmapped + * by libxl_domain_build/restore. If either of these are never called + * then the user is responsible for calling + * libxl_file_reference_unmap. + */ typedef struct { int max_vcpus; int cur_vcpus; @@ -98,7 +116,7 @@ typedef struct { uint32_t video_memkb; uint32_t shadow_memkb; bool disable_migrate; - const char *kernel; + libxl_file_reference kernel; int hvm; union { struct { @@ -115,7 +133,7 @@ typedef struct { struct { uint32_t slack_memkb; const char *cmdline; - const char *ramdisk; + libxl_file_reference ramdisk; const char *features; } pv; } u; @@ -308,6 +326,9 @@ int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid); int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req); int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force); +int libxl_file_reference_map(struct libxl_ctx *ctx, libxl_file_reference *f); +int libxl_file_reference_unmap(struct libxl_ctx *ctx, libxl_file_reference *f); + char *libxl_uuid2string(struct libxl_ctx *ctx, uint8_t uuid[16]); /* 0 means ERROR_ENOMEM, which we have logged */ diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 787d6c7a32..3b398cb5db 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -143,22 +143,76 @@ int build_pv(struct libxl_ctx *ctx, uint32_t domid, int ret; int flags = 0; + xc_dom_loginit(ctx->xch); + dom = xc_dom_allocate(ctx->xch, info->u.pv.cmdline, info->u.pv.features); if (!dom) { XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_allocate failed"); - return -1; + return ERROR_FAIL; + } + + if (info->kernel.mapped) { + if ( (ret = xc_dom_kernel_mem(dom, info->kernel.data, info->kernel.size)) != 0) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_kernel_mem failed"); + goto out; + } + } else { + if ( (ret = xc_dom_kernel_file(dom, info->kernel.path)) != 0) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_kernel_file failed"); + goto out; + } } - ret = xc_dom_linux_build(ctx->xch, dom, domid, info->target_memkb / 1024, - info->kernel, info->u.pv.ramdisk, flags, - state->store_port, &state->store_mfn, - state->console_port, &state->console_mfn); - if (ret != 0) { - xc_dom_release(dom); - XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "xc_dom_linux_build failed"); - return -2; + + if ( info->u.pv.ramdisk.path && strlen(info->u.pv.ramdisk.path) ) { + if (info->u.pv.ramdisk.mapped) { + if ( (ret = xc_dom_ramdisk_mem(dom, info->u.pv.ramdisk.data, info->u.pv.ramdisk.size)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_ramdisk_mem failed"); + goto out; + } + } else { + if ( (ret = xc_dom_ramdisk_file(dom, info->u.pv.ramdisk.path)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_ramdisk_file failed"); + goto out; + } + } } + + dom->flags = flags; + dom->console_evtchn = state->console_port; + dom->xenstore_evtchn = state->store_port; + + if ( (ret = xc_dom_boot_xen_init(dom, ctx->xch, domid)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_xen_init failed"); + goto out; + } + if ( (ret = xc_dom_parse_image(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_parse_image failed"); + goto out; + } + if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_mem_init failed"); + goto out; + } + if ( (ret = xc_dom_boot_mem_init(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_mem_init failed"); + goto out; + } + if ( (ret = xc_dom_build_image(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_build_image failed"); + goto out; + } + if ( (ret = xc_dom_boot_image(dom)) != 0 ) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xc_dom_boot_image failed"); + goto out; + } + + state->console_mfn = xc_dom_p2m_host(dom, dom->console_pfn); + state->store_mfn = xc_dom_p2m_host(dom, dom->xenstore_pfn); + + ret = 0; +out: xc_dom_release(dom); - return 0; + return ret == 0 ? 0 : ERROR_FAIL; } int build_hvm(struct libxl_ctx *ctx, uint32_t domid, @@ -166,12 +220,17 @@ int build_hvm(struct libxl_ctx *ctx, uint32_t domid, { int ret; + if (info->kernel.mapped) { + XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "build_hvm kernel cannot be mmapped"); + return ERROR_INVAL; + } + ret = xc_hvm_build_target_mem( ctx->xch, domid, (info->max_memkb - info->video_memkb) / 1024, (info->target_memkb - info->video_memkb) / 1024, - libxl_abs_path(ctx, (char *)info->kernel, + libxl_abs_path(ctx, (char *)info->kernel.path, libxl_xenfirmwaredir_path())); if (ret) { XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "hvm building failed"); diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 090e369712..c355505ae5 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -196,7 +196,7 @@ static void init_build_info(libxl_domain_build_info *b_info, libxl_domain_create if (c_info->hvm) { b_info->shadow_memkb = 0; /* Set later */ b_info->video_memkb = 8 * 1024; - b_info->kernel = "hvmloader"; + b_info->kernel.path = "hvmloader"; b_info->hvm = 1; b_info->u.hvm.pae = 1; b_info->u.hvm.apic = 1; @@ -366,7 +366,7 @@ static void printf_info(int domid, printf("\t(image\n"); if (c_info->hvm) { printf("\t\t(hvm\n"); - printf("\t\t\t(loader %s)\n", b_info->kernel); + printf("\t\t\t(loader %s)\n", b_info->kernel.path); printf("\t\t\t(video_memkb %d)\n", b_info->video_memkb); printf("\t\t\t(shadow_memkb %d)\n", b_info->shadow_memkb); printf("\t\t\t(pae %d)\n", b_info->u.hvm.pae); @@ -397,9 +397,9 @@ static void printf_info(int domid, printf("\t\t)\n"); } else { printf("\t\t(linux %d)\n", b_info->hvm); - printf("\t\t\t(kernel %s)\n", b_info->kernel); + printf("\t\t\t(kernel %s)\n", b_info->kernel.path); printf("\t\t\t(cmdline %s)\n", b_info->u.pv.cmdline); - printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk); + printf("\t\t\t(ramdisk %s)\n", b_info->u.pv.ramdisk.path); printf("\t\t)\n"); } printf("\t)\n"); @@ -563,7 +563,7 @@ static void parse_config_data(const char *configfile_filename_report, b_info->video_memkb = l * 1024; if (!xlu_cfg_get_string (config, "kernel", &buf)) - b_info->kernel = strdup(buf); + b_info->kernel.path = strdup(buf); if (c_info->hvm == 1) { if (!xlu_cfg_get_long (config, "pae", &l)) @@ -603,7 +603,7 @@ static void parse_config_data(const char *configfile_filename_report, b_info->u.pv.cmdline = cmdline; if (!xlu_cfg_get_string (config, "ramdisk", &buf)) - b_info->u.pv.ramdisk = strdup(buf); + b_info->u.pv.ramdisk.path = strdup(buf); } if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) { diff --git a/tools/ocaml/libs/xl/xl_stubs.c b/tools/ocaml/libs/xl/xl_stubs.c index 4e8d45ea2e..0f523ee2d4 100644 --- a/tools/ocaml/libs/xl/xl_stubs.c +++ b/tools/ocaml/libs/xl/xl_stubs.c @@ -120,7 +120,7 @@ static int domain_build_info_val (libxl_domain_build_info *c_val, value v) c_val->target_memkb = Int64_val(Field(v, 3)); c_val->video_memkb = Int64_val(Field(v, 4)); c_val->shadow_memkb = Int64_val(Field(v, 5)); - c_val->kernel = String_val(Field(v, 6)); + c_val->kernel.path = String_val(Field(v, 6)); c_val->hvm = Tag_val(Field(v, 7)) == 0; infopriv = Field(Field(v, 7), 0); if (c_val->hvm) { @@ -136,7 +136,7 @@ static int domain_build_info_val (libxl_domain_build_info *c_val, value v) } else { c_val->u.pv.slack_memkb = Int64_val(Field(infopriv, 0)); c_val->u.pv.cmdline = String_val(Field(infopriv, 1)); - c_val->u.pv.ramdisk = String_val(Field(infopriv, 2)); + c_val->u.pv.ramdisk.path = String_val(Field(infopriv, 2)); c_val->u.pv.features = String_val(Field(infopriv, 3)); } -- 2.30.2